<?php
/**
 * unicode字符解码
 * @param $name
 * @return string
 */
function unicode_decode($name)
{

    $json = '{"str":"' . $name . '"}';
    $arr = json_decode($json, true);
    if (empty($arr)) return '';
    return $arr['str'];
}

/**
 * @param $length
 * @return string
 * 获取随机的字符串
 */
function getRandChars($length)
{
    $str = '';
    $strPol = 'QWERTYUIOPASDFGHJKLXCVBNM1234567890qwertyuiopasdfghjklzxcvbnm';
    $max = strlen($strPol) - 1;
    for ($i = 0; $i < $length; $i++) {
        $str .= $strPol[rand(0, $max)];
    }
    return $str;
}

/**
 * 下划线转驼峰
 * 思路:
 * step1.原字符串转小写,原字符串中的分隔符用空格替换,在字符串开头加上分隔符
 * step2.将字符串中每个单词的首字母转换为大写,再去空格,去字符串首部附加的分隔符.
 */
function camelize($uncamelized_words, $separator = '_')
{
    $uncamelized_words = $separator . str_replace($separator, " ", strtolower($uncamelized_words));
    return ltrim(str_replace(" ", "", ucwords($uncamelized_words)), $separator);
}

/**
 * 将下划线转化为首字母大写的类名
 * @param $uncamelized_words
 * @param string $separator
 * @return string
 */
function camelizeClass($uncamelized_words, $separator = '_')
{
    $uncamelized_words = str_replace($separator, " ", strtolower($uncamelized_words));
    return ltrim(str_replace(" ", "", ucwords($uncamelized_words)), $separator);
}

/**
 * 驼峰命名转下划线命名
 * 思路:
 * 小写和大写紧挨一起的地方,加上分隔符,然后全部转小写
 */
function uncamelize($camelCaps, $separator = '_')
{
    return strtolower(preg_replace('/([a-z])([A-Z])/', "$1" . $separator . "$2", $camelCaps));
}

/**
 * +----------------------------------------------------------
 * 把返回的数据集转换成Tree
 * +----------------------------------------------------------
 * @access public
 * +----------------------------------------------------------
 * @param array $list 要转换的数据集
 * @param string $pid parent标记字段
 * @param string $level level标记字段
 * +----------------------------------------------------------
 * @return array
 * +----------------------------------------------------------
 */
function listToTree($list, $pk = 'id', $pid = 'pid', $child = '_child', $root = 0)
{
    // 创建Tree
    $tree = array();
    if (is_array($list)) {
        // 创建基于主键的数组引用
        $refer = array();
        foreach ($list as $key => $data) {
            $refer[$data[$pk]] =& $list[$key];
        }
        foreach ($list as $key => $data) {
            // 判断是否存在parent
            $parentId = $data[$pid];
            if ($root == $parentId) {
                $tree[] =& $list[$key];
            } else {
                if (isset($refer[$parentId])) {
                    $parent =& $refer[$parentId];
                    $parent[$child][] =& $list[$key];
                }
            }
        }
    }
    return $tree;
}

/**
 * 经典的概率算法，可用于刮刮卡，大转盘等抽奖算法
 * $proArr是一个预先设置的数组，
 * 假设数组为：array(100,200,300，400)，
 * 开始是从1,1000 这个概率范围内筛选第一个数是否在他的出现概率范围之内，
 * 如果不在，则将概率空间，也就是k的值减去刚刚的那个数字的概率空间，
 * 在本例当中就是减去100，也就是说第二个数是在1，900这个范围内筛选的。
 * 这样 筛选到最终，总会有一个数满足要求。
 * 就相当于去一个箱子里摸东西，
 * 第一个不是，第二个不是，第三个还不是，那最后一个一定是。
 * 这个算法简单，而且效率非常 高，
 * 关键是这个算法已在我们以前的项目中有应用，尤其是大数据量的项目中效率非常棒。
 * 用法参考网址：http://blog.csdn.net/dongsg11200/article/details/24607877
 * @return integer 返回数组索引
 */
function getPrizeRand($proArr) {
    $result = '';
    //概率数组的总概率精度
    $proSum = array_sum($proArr);
    //概率数组循环
    foreach ($proArr as $key => $proCur) {
        $randNum = mt_rand(1, $proSum);
        if ($randNum <= $proCur) {
            $result = $key;
            break;
        } else {
            $proSum -= $proCur;
        }
    }
    unset ($proArr);
    return $result;
}
/**
 * 多维数组的指定多个字段排序
 * 示例：sortArrByManyField($list, 'order_num', SORT_ASC, 'id', SORT_DESC);
 * @return mixed|null
 * @throws Exception
 */
function sortArrByManyField()
{
    $args = func_get_args();
    if (empty($args)) {
        return null;
    }
    $arr = array_shift($args);
    if (!is_array($arr)) {
        throw new Exception("第一个参数不为数组");
    }
    foreach ($args as $key => $field) {
        if (is_string($field)) {
            $temp = array();
            foreach ($arr as $index => $val) {
                $temp[$index] = $val[$field];
            }
            $args[$key] = $temp;
        }
    }
    $args[] = &$arr;//引用值
    call_user_func_array('array_multisort', $args);
    return array_pop($args);
}

/**
 * 获取两个日期之间所有日期
 * @param $startDate
 * @param $endDate
 * @return array
 */
function getDatesBetweenTwoDays($startDate, $endDate)
{
    //开始结束日期位置不对，互换数据
    if ($startDate > $endDate) {
        list($startDate, $endDate) = [$endDate, $startDate];
    }
    $dates = [];
    if (strtotime($startDate) > strtotime($endDate)) {
        //如果开始日期大于结束日期，直接return 防止下面的循环出现死循环
        return $dates;
    } elseif ($startDate == $endDate) {
        //开始日期与结束日期是同一天时
        array_push($dates, $startDate);
        return $dates;
    } else {
        array_push($dates, $startDate);
        $currentDate = $startDate;
        do {
            $nextDate = date('Y-m-d', strtotime($currentDate . ' +1 days'));
            array_push($dates, $nextDate);
            $currentDate = $nextDate;
        } while ($endDate != $currentDate);
        return $dates;
    }
}

/**
 * 按日期格式化表格数据方法
 * @param array $originData 原始二位数组数据
 * @param string $dateKey 时间维度key
 * @param array $dataKeys 数据集key
 * @param string $startDate 开始日期
 * @param string $endDate 结束日期
 * @throws Exception
 */
function formatChartDataByDate($originData = [], $dateKey = '', $dataKeys = [], $startDate = '', $endDate = '')
{
    //先按日期排序
    $sortByLabelKey = sortArrByManyField($originData, $dateKey, SORT_ASC);
    //以日期key重组数据
    $dateKeyGroupList = [];
    if (!empty($sortByLabelKey)) {
        foreach ($sortByLabelKey as $item) {
            if (isset($item[$dateKey])) {
                $dateKeyGroupList[$item[$dateKey]] = $item;
            }
        }
    }
    //时间维度列表
    $startDate || $startDate = date('Y-m-d', strtotime('-7 days'));
    $endDate || $endDate = date('Y-m-d', strtotime('-1 days'));
    $dateList = getDatesBetweenTwoDays($startDate, $endDate);
    //检索原始数据并合成格式化数据
    $dataSet = [];
    foreach ($dateList as $dateVal) {
        foreach ($dataKeys as $fieldKey) {
            isset($dataSet[$fieldKey]) || $dataSet[$fieldKey] = [];
            if (isset($dateKeyGroupList[$dateVal][$fieldKey])) {
                $dataSet[$fieldKey][] = (float)$dateKeyGroupList[$dateVal][$fieldKey];
            } else {
                $dataSet[$fieldKey][] = 0;
            }
        }
    }
    return ['dateList' => $dateList, 'dateSet' => $dataSet];
}

/**
 * 按小时格式化表格数据方法
 * @param array $originData 原始二位数组数据
 * @param string $dateKey 时间维度key
 * @param array $dataKeys 数据集key
 * @throws Exception
 */
function formatChartDataByHour($originData = [], $dateKey = '', $dataKeys = [])
{
    //先按日期排序
    $sortByLabelKey = sortArrByManyField($originData, $dateKey, SORT_ASC);
    //以日期key重组数据
    $dateKeyGroupList = [];
    if (!empty($sortByLabelKey)) {
        foreach ($sortByLabelKey as $item) {
            if (isset($item[$dateKey])) {
                $dateKeyGroupList[$item[$dateKey]] = $item;
            }
        }
    }
    //时间维度列表
    $hourList = [];
    for ($i = 0; $i <= 2300; $i += 100) {
        $hourList[] = $i;
    }
    //检索原始数据并合成格式化数据
    $dataSet = [];
    foreach ($hourList as $dateVal) {
        foreach ($dataKeys as $fieldKey) {
            isset($dataSet[$fieldKey]) || $dataSet[$fieldKey] = [];
            if (isset($dateKeyGroupList[$dateVal][$fieldKey])) {
                $dataSet[$fieldKey][] = (float)$dateKeyGroupList[$dateVal][$fieldKey];
            } else {
                $dataSet[$fieldKey][] = 0;
            }
        }
    }
    //转换时间格式
    $hourList = array_map(function ($hourNum) {
        $hourNum = str_pad($hourNum, 4, '0', STR_PAD_LEFT);
        return date('H:i', strtotime($hourNum));
    }, $hourList);
    return ['dateList' => $hourList, 'dateSet' => $dataSet];
}

/**
 * 获取指定年份所有周列表
 * @param $year
 */
function getWeeksByYear($year = '')
{
    $year || $year = date('Y');
    //获取当年首个周一所在日期
    $yearStart = $year . '-01-01';
    do {
        $weekNum = date('w', strtotime($yearStart));
        $firstWeekDay = $yearStart;
        $yearStart = date('Y-m-d', strtotime($yearStart . ' +1 days'));
    } while ((int)$weekNum != 1);
    //收集所有周一列表
    $weekList = [];
    do {
        $weekList[] = $firstWeekDay;
        $firstWeekDay = date('Y-m-d', strtotime($firstWeekDay . ' +1 week'));
    } while (date('Y', strtotime($firstWeekDay)) == $year && strtotime($firstWeekDay) <= time());
    return $weekList;
}

/**
 * 按周格式化表格数据方法
 * @param array $originData 原始二位数组数据
 * @param string $dateKey 时间维度key
 * @param array $dataKeys 数据集key
 * @param string $year 年份
 * @return array
 * @throws Exception
 */
function formatChartDataByWeek($originData = [], $dateKey = '', $dataKeys = [], $year = '')
{
    //先按日期排序
    $sortByLabelKey = sortArrByManyField($originData, $dateKey, SORT_ASC);
    //以日期key重组数据
    $dateKeyGroupList = [];
    if (!empty($sortByLabelKey)) {
        foreach ($sortByLabelKey as $item) {
            if (isset($item[$dateKey])) {
                $dateKeyGroupList[$item[$dateKey]] = $item;
            }
        }
    }
    //时间维度列表
    $weekList = getWeeksByYear($year);
    //检索原始数据并合成格式化数据
    $dataSet = [];
    foreach ($weekList as $dateVal) {
        foreach ($dataKeys as $fieldKey) {
            isset($dataSet[$fieldKey]) || $dataSet[$fieldKey] = [];
            if (isset($dateKeyGroupList[$dateVal][$fieldKey])) {
                $dataSet[$fieldKey][] = (float)$dateKeyGroupList[$dateVal][$fieldKey];
            } else {
                $dataSet[$fieldKey][] = 0;
            }
        }
    }
    return ['dateList' => $weekList, 'dateSet' => $dataSet];
}

/**
 * 获取指定年份所有月列表
 * @param $year
 */
function getMonthsByYear($year = '')
{
    $year || $year = date('Y');
    //获取当年shou周一所在日期
    $yearStart = $year . '-01-01';
    //收集所有周一列表
    $dayList = [];
    do {
        $dayList[] = $yearStart;
        $yearStart = date('Y-m-d', strtotime($yearStart . ' +1 month'));
    } while (date('Y', strtotime($yearStart)) == $year && strtotime($yearStart) <= time());
    return $dayList;
}

/**
 * 按月格式化表格数据方法
 * @param array $originData 原始二位数组数据
 * @param string $dateKey 时间维度key
 * @param array $dataKeys 数据集key
 * @param string $year 年份
 * @return array
 * @throws Exception
 */
function formatChartDataByMonth($originData = [], $dateKey = '', $dataKeys = [], $year = '')
{
    //先按日期排序
    $sortByLabelKey = sortArrByManyField($originData, $dateKey, SORT_ASC);
    //以日期key重组数据
    $dateKeyGroupList = [];
    if (!empty($sortByLabelKey)) {
        foreach ($sortByLabelKey as $item) {
            if (isset($item[$dateKey])) {
                $dateKeyGroupList[$item[$dateKey]] = $item;
            }
        }
    }
    //时间维度列表
    $monthList = getMonthsByYear($year);
    //检索原始数据并合成格式化数据
    $dataSet = [];
    foreach ($monthList as $dateVal) {
        foreach ($dataKeys as $fieldKey) {
            isset($dataSet[$fieldKey]) || $dataSet[$fieldKey] = [];
            if (isset($dateKeyGroupList[$dateVal][$fieldKey])) {
                $dataSet[$fieldKey][] = (float)$dateKeyGroupList[$dateVal][$fieldKey];
            } else {
                $dataSet[$fieldKey][] = 0;
            }
        }
    }
    //转换时间格式
    $monthList = array_map(function ($monthStr) {
        return date('Y-m', strtotime($monthStr));
    }, $monthList);
    return ['dateList' => $monthList, 'dateSet' => $dataSet];
}